package cn.com.generaldata.os.exporter;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;

import cn.com.generaldata.os.constant.FilterConstant;
import cn.com.generaldata.os.constant.ReportConstant;
import cn.com.generaldata.os.newpojo.ReportType;
import cn.com.generaldata.os.paging.Filter;
import cn.com.generaldata.os.paging.FilterRule;
import cn.com.generaldata.os.paging.Page;
import cn.com.generaldata.os.pojo.Report;
import cn.com.generaldata.os.pojo.ReportDetail;
import cn.com.generaldata.os.pojo.mvc.Row;
import cn.com.generaldata.os.report.xml.ReportExporter;
import cn.com.generaldata.os.service.intf.ReportServiceInterface;
import cn.com.generaldata.os.util.BeanMapper;

public class Exporter {

	private static Log log = LogFactory.getLog(Exporter.class);
	public static boolean flag;
	private static final String HEADER = "[OS][Export]";
	private static final String CONFIGURATION_ITEM_EXPORT_PATH = "export.path";
	private static final String EXPORT_CONFIGURATION_FILE = "global_conf.properties";
	private static final String EXPORT_RESULT_FILE = "export_result.properties";
	private static final String EXPORT_FILE = "export_report";
	private static final String EXPORT_ROOT_DIR = "D:";

	private ReportServiceInterface reportService;

	@SuppressWarnings("unchecked")
	private List<ReportType> queryReportTypes() {
		Filter filter = new Filter();
		filter.setOrder(FilterConstant.ASC);
		filter.setSortBy("typeCode");
		return (List<ReportType>) reportService.queryReportTypes(filter, null).getOperationResult();
	}

	// @SuppressWarnings("unchecked")
	// private List<Report> queryReports(Date startingDate, String reportTypeCode, Integer maxNum) {
	// Filter filter = new Filter();
	// filter.setOrder(FilterConstant.ASC);
	// filter.setSortBy("reportCheckSuccessDate");
	//
	// filter.addRule(new FilterRule(FilterConstant.EQUAL, "reportTypeCode", reportTypeCode));
	// filter.addRule(new FilterRule(FilterConstant.EQUAL, "reportCheckStatus",
	// Short.valueOf(ReportConstant.FLAG_PASSED)));
	// filter.addRule(new FilterRule(FilterConstant.GT, "reportCheckSuccessDate", startingDate));
	//
	// Page page = null;
	// if (maxNum != null) {
	// page = new Page(1, maxNum);
	// }
	//
	// return (List<Report>) reportService.queryReports(filter, page).getOperationResult();
	// }

	@SuppressWarnings("unchecked")
	private List<Report> queryReports(String userId, String areaId, Date startingDate, String reportTypeCode,
			Integer maxNum) {
		Filter filter = new Filter();
		filter.setOrder(FilterConstant.ASC);
		filter.setSortBy("reportCreateTime");

		filter.addRule(new FilterRule(FilterConstant.EQUAL, "reportTypeCode", reportTypeCode));

		// 自己加
		if (userId != null) {
			filter.addRule(new FilterRule(FilterConstant.EQUAL, "user.id", userId));
		}

		if (areaId != null) {
			filter.addRule(new FilterRule(FilterConstant.EQUAL, "area.id", areaId));
		}

		Short[] flag_committeds = { 1, 6 };

		filter.addRule(new FilterRule(FilterConstant.COLLECTION, "reportCheckStatus", flag_committeds));
		filter.addRule(new FilterRule(FilterConstant.GT, "reportCreateTime", startingDate));
		filter.addRule(new FilterRule(FilterConstant.OR, "reportReferenceId", ""));

		Page page = null;
		if (maxNum != null) {
			page = new Page(1, maxNum);
		}

		return (List<Report>) reportService.queryReports(filter, page).getOperationResult();
	}

	@SuppressWarnings("unchecked")
	private List<ReportDetail> queryReportDetailsByReportId(String id) {
		Filter filter = new Filter();
		filter.setOrder(FilterConstant.ASC);
		filter.setSortBy("rowIndex");

		filter.addRule(new FilterRule(FilterConstant.EQUAL, "report.id", id));
		filter.addRule(new FilterRule(FilterConstant.EQUAL, "rowType", Integer.valueOf(ReportConstant.ROW_TYPE_DATA)));

		List<ReportDetail> reportDetails = new ArrayList<ReportDetail>();
		for (ReportDetail reportDetail : (List<ReportDetail>) reportService.queryReportDetails(filter, null)
				.getOperationResult()) {
			reportDetails.add(replaceSpace(reportDetail));
		}

		return (List<ReportDetail>) reportService.queryReportDetails(filter, null).getOperationResult();
	}

	private ReportDetail replaceSpace(ReportDetail reportDetail) {
		reportDetail.setF1(reportDetail.getF1() == null ? null : reportDetail.getF1().replaceAll("　", "").trim());
		reportDetail.setF2(reportDetail.getF2() == null ? null : reportDetail.getF2().replaceAll("　", "").trim());
		reportDetail.setF3(reportDetail.getF3() == null ? null : reportDetail.getF3().replaceAll("　", "").trim());
		reportDetail.setF4(reportDetail.getF4() == null ? null : reportDetail.getF4().replaceAll("　", "").trim());
		reportDetail.setF5(reportDetail.getF5() == null ? null : reportDetail.getF5().replaceAll("　", "").trim());
		reportDetail.setF6(reportDetail.getF6() == null ? null : reportDetail.getF6().replaceAll("　", "").trim());
		reportDetail.setF7(reportDetail.getF7() == null ? null : reportDetail.getF7().replaceAll("　", "").trim());
		reportDetail.setF8(reportDetail.getF8() == null ? null : reportDetail.getF8().replaceAll("　", "").trim());
		reportDetail.setF9(reportDetail.getF9() == null ? null : reportDetail.getF9().replaceAll("　", "").trim());
		reportDetail.setF10(reportDetail.getF10() == null ? null : reportDetail.getF10().replaceAll("　", "").trim());
		reportDetail.setF11(reportDetail.getF11() == null ? null : reportDetail.getF11().replaceAll("　", "").trim());
		reportDetail.setF12(reportDetail.getF12() == null ? null : reportDetail.getF12().replaceAll("　", "").trim());
		reportDetail.setF13(reportDetail.getF13() == null ? null : reportDetail.getF13().replaceAll("　", "").trim());
		reportDetail.setF14(reportDetail.getF14() == null ? null : reportDetail.getF14().replaceAll("　", "").trim());
		reportDetail.setF15(reportDetail.getF15() == null ? null : reportDetail.getF15().replaceAll("　", "").trim());
		return reportDetail;
	}

	private List<cn.com.generaldata.os.pojo.mvc.Report> generateMVCReports(List<Report> reports) {
		List<cn.com.generaldata.os.pojo.mvc.Report> mvcReports = new ArrayList<cn.com.generaldata.os.pojo.mvc.Report>();

		for (Report report : reports) {
			List<ReportDetail> reportDetails = queryReportDetailsByReportId(report.getId());
			mvcReports.add(toMVCReport(report, reportDetails));
		}

		return mvcReports;
	}

	public String getExportPath() {
		try {
			String webRootPath = new ClassPathResource("/").getFile().getParentFile().getParentFile().getAbsolutePath();
			Properties properties = getProperties(EXPORT_CONFIGURATION_FILE);

			String exportPath = properties.getProperty(CONFIGURATION_ITEM_EXPORT_PATH, "/export");
			if (new File(exportPath).isAbsolute()) {
				return new File(exportPath).getAbsolutePath();
			}

			String path = webRootPath + exportPath;
			// System.out.println("webRootPath: " + webRootPath );
			// System.out.println("path: " + path );
			return path;
		} catch (IOException e) {
			log.error(HEADER + "[getExportPath]" + e.getMessage());
			return null;
		}

	}

	private Date getLastExportDate(String typeCode) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Properties properties = getProperties(EXPORT_RESULT_FILE);

		try {
			// System.out.println(date);
			return formatter.parse(properties.getProperty(typeCode, "1900-01-01 00:00:00"));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	private String generateTypeDir(String typeName) {
		String exportDir = getExportPath() + "/" + typeName + "/";
		// String exportDir = EXPORT_ROOT_DIR + File.separator + EXPORT_FILE + File.separator + typeName + "/";
		File file = new File(exportDir);
		if (!file.exists()) {
			file.mkdirs();
		}
		// System.out.println(exportDir);
		return exportDir;
	}

	private TreeMap<String, String> initExportResult() {
		TreeMap<String, String> result = new TreeMap<String, String>();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		List<ReportType> reportTypes = queryReportTypes();
		for (ReportType reportType : reportTypes) {
			String date = formatter.format(getLastExportDate(reportType.getTypeCode()));
			result.put(reportType.getTypeCode(), date);
		}
		return result;
	}

	private void storeExportResult(TreeMap<String, String> exportResult) {
		ClassPathResource resource = new ClassPathResource("export_result.properties");
		FileOutputStream fos = null;
		OutputStreamWriter osw = null;
		BufferedWriter bw = null;
		try {
			fos = new FileOutputStream(resource.getFile().getAbsoluteFile());
			osw = new OutputStreamWriter(fos, "UTF-8");
			bw = new BufferedWriter(osw);
			for (Entry<String, String> entry : exportResult.entrySet()) {
				bw.write(entry.getKey() + "=" + entry.getValue() + "\n");
				bw.flush();
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (bw != null) {
					bw.close();
				}
				if (osw != null) {
					osw.close();
				}
				if (fos != null) {
					fos.close();
				}
			} catch (Exception e) {
			}
		}
	}

	public String export(String userId, String areaId) {
		return export(userId, areaId, null);
	}

	public String export(String userId, String areaId, Integer maxNum) {
		log.info(HEADER + "[export]Begin to export reports.");
		List<String> result = new ArrayList<String>();
		String fileName = null;
		// boolean flag;

		// 获得所有报表类型，以供分类导出
		List<ReportType> reportTypes = queryReportTypes();

		SimpleDateFormat formatterFileName = new SimpleDateFormat("yyyyMMddHHmmss");
		SimpleDateFormat formatterExportResult = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		// 初始化报表导出结果的Map，Key为ReportTypeCode，Value为最后一次成功导出的时间
		TreeMap<String, String> exportResult = initExportResult();

		for (ReportType reportType : reportTypes) {
			Date lastExportDate = getLastExportDate(reportType.getTypeCode());
			List<cn.com.generaldata.os.pojo.mvc.Report> reports = generateMVCReports(queryReports(userId, areaId,
					lastExportDate, reportType.getTypeCode(), maxNum));

			if (reports.size() > 0) {
				log.info(HEADER + "[export]Found " + reports.size() + " result(s) of type "
						+ reports.get(0).getReportType() + ".");
			}

			for (cn.com.generaldata.os.pojo.mvc.Report report : reports) {
				// fileName = generateTypeDir(reportType.getTypeCode() + "_" + reportType.getTypeName())
				// + reportType.getTypeCode() + "_" + formatterFileName.format(report.getCheckSuccessDate())
				// + System.currentTimeMillis() + ".xml";

				// 自加
				fileName = generateTypeDir(reportType.getTypeCode() + "_" + reportType.getTypeName())
						+ reportType.getTypeCode() + "_" + formatterFileName.format(report.getCreateDate())
						+ System.currentTimeMillis() + ".xml";

				flag = ReportExporter.exportReport(report, fileName);
				if (flag) {
					log.info(HEADER + "[export]Export the file " + fileName + ".");
					// exportResult.put(reportType.getTypeCode(),
					// formatterExportResult.format(report.getCheckSuccessDate()));
					exportResult.put(reportType.getTypeCode(), formatterExportResult.format(report.getCreateDate()));
				} else {
					log.error(HEADER + "[export]Export file " + fileName + " with error.");
					result.add("Error: ID: " + report.getReportId() + ".");
				}
			}
		}

		storeExportResult(exportResult);
		log.debug(HEADER + "[export]Store the export result.");
		log.info(HEADER + "[export]Finish report exporting.");

		// System.out.println("fileName: " + fileName);
		return getExportPath();
	}

	public Properties getProperties(String path) {
		ClassPathResource resource = new ClassPathResource(path);
		Properties properties = new Properties();
		InputStream is = null;
		try {
			File file = resource.getFile();
			is = new FileInputStream(file.getAbsoluteFile());
			properties.load(is);
		} catch (FileNotFoundException e) {
			log.debug(HEADER + "[getProperties]The configuration file doesn't exist.");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {

				}
			}
		}

		return properties;
	}

	private cn.com.generaldata.os.pojo.mvc.Report toMVCReport(Report report, List<ReportDetail> reportDetails) {
		List<Row> rows = new ArrayList<Row>();
		for (ReportDetail reportDetail : reportDetails) {
			Row row = BeanMapper.map(reportDetail, Row.class);
			row.setRowId(reportDetail.getId());
			rows.add(row);
		}

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

		return new cn.com.generaldata.os.pojo.mvc.Report(String.valueOf(report.getId()), String.valueOf(report
				.getReportReferenceId()), report.getReportType(), report.getReportTypeCode(), String.valueOf(report
				.getUser().getId()), report.getReportRegionName(), report.getReportRegionOcean(),
				report.getReportCityName(), report.getReportDepartmentName(), report.getReportRegionCode(),
				report.getReportUnit(), report.getReportUnitIndustry(), report.getReportUnitIndustryId(),
				report.getReportInstitutionName(), report.getReportInstitutionCode(), report.getReportDomainName(),
				report.getReportDomainCode(), report.getReportYear(), report.getReportQuarter(), report.getReportNo(),
				report.getReportAdmin(), report.getReportApproveAdmin(), report.getReportApproveNo(),
				report.getReportExpireDate(), report.getReportMeasureUnit(), report.getReportUnitAdmin(),
				report.getReportStatAdmin(), report.getReportFillAdmin(), formatter.format(report.getReportDate()),
				report.getReportOrigin(), report.getReportSupplyOrigin(), report.getReportDesc(),
				report.getReportCreateTime(), report.getReportLastEditTime(), String.valueOf(report.getOperator()
						.getId()), String.valueOf(report.getArea().getId()), Byte.valueOf(String.valueOf(report
						.getReportCheckStatus())), report.getReportCheckComment(), report.getReportCheckResult(),
				report.getReportCheckSuccessDate(), report.getReportRemark(), report.getReportFlag(),
				report.getReportProxyId(), rows, report.getReportTimetype(), report.getReportMonth(),
				report.getReportYearTime(), report.getReportVersion(), report.getReportTypeId(),
				report.getReportEdition(), report.getSelfSet1(), report.getSelfSet2(), report.getSelfSet3(),
				report.getSelfSet4(), report.getSelfSet5(), report.getQuarter(), report.getMonth(), report.getUnitId(),
				report.getUpdateTime());
	}

	public void setReportService(ReportServiceInterface reportService) {
		this.reportService = reportService;
	}

}
